use futures::executor::block_on;
use futures::join;
use std::thread; //引入线程模块
use std::time::Duration;
use threadpool::ThreadPool; //引入时间模块
fn main() {
    //one(); //线程管理
    //two(); //线程与move闭包
    //three();//线程池
    //four();//并发

    //five(); // 多个异步函数实例
    six();//多个异步函数示例2
}
fn one() {
    // 创建第一个子线程
    let thread_1 = thread::spawn(|| {
        for i in 1..=5 {
            println!("数字 {} 来自thread_1", i);
            thread::sleep(Duration::from_secs(2));
        }
    });
    // 创建第二个子线程

    let thread_2 = thread::spawn(|| {
        for i in 1..=5 {
            println!("数字 {} 来自thread_2", i);
            thread::sleep(Duration::from_secs(4));
        }
    });

    for i in 1..=5 {
        println!("数字 {} 来自 main", i);
        thread::sleep(Duration::from_secs(8));
    }

    //阻塞主线程直到子线程执行结束
    thread_1.join().unwrap(); //。join的位置会直接影响执行顺序
    thread_2.join().unwrap();
}

fn two() {
    let v = vec![1, 2, 3, 5, 6];
    //let handle = thread::spawn(|| {println!("{:?}", v)});
    // 子线程使用了主线程的动态数组v，并使其成为闭包环境的一部分。编译代码，会使得到如下错误提示。

    let handle = thread::spawn(move || println!("{:?}", v));
    // move 关键字来强制闭包获取动态数组v的所有权，保证主线程上不会使用动态数组v
    //let v1 = v;
    //println!("{:?}", v1);
    // v的所有权交给了子线程，主线程不能操作
    handle.join().unwrap();
}

fn three() {
    //线程池
    /*
    cargo.toml加载模块
        [dependencies]
        threadpool = "1.8.1"
        */
    let pool = ThreadPool::new(3);
    for i in 1..=5 {
        pool.execute(move || {
            // 与thread::spawn类似可以接受闭包，闭包在当前线程中执行
            println!("数字{} 来自线程1", i);
        })
    }
    for i in 1..=5 {
        pool.execute(move || {
            println!("数字{} 来自线程2", i);
        })
    }
    for i in 1..=5 {
        pool.execute(move || {
            println!("数字{} 来自线程3", i);
        })
    }

    pool.join(); // 阻塞主线程等待线程池中的任务执行完毕
}
/*
[dependencies]
futures = "0.1"
异步并发
当个线程中并发执行多个任务，想多多个线程并发执行多个任务可以减少线程切换和线程共享数据时减少产生的系统开销，以及空跑线程会占用的系统资源
*/
// async/.await语法
/*
通过future并发模型和async/.await方案来实现异步并发
async/.await是rust内置语法，可以使异步代码像普通代码易于编写。async和.await是两个可以分开理解的术语
async 通常跟fn函数定义一起使用，用于创建异步函数，返回值的类型实现了Future trait，而这个返回值需要由执行器来执行，比如block_on会阻塞当前线程来执行future，直到有结果返回
.await 不阻塞当前线程，异步等待future完成，在对当前future无法执行时，.await将调度当前future让出线程控制权，由其他future继续执行，这个语法只有future对象才能调用，
必须在async函数内使用
*/
fn four() {
    let future = hello_async();
    block_on(future) // 必须使用block_on来执行 才会打印hello async
}

async fn hello_async() {
    println!("hello async")
}

async fn learn_data_structure() -> String {
    println!("学习数学结构");
    "学习数学结构".to_string()
}
async fn learn_algorithm(data: String) {
    println!("学习算法");
    println!("{}", data);
}
async fn learn_rust() {
    println!("学习rust");
}
fn five() {
    let data = block_on(learn_data_structure());
    block_on(learn_algorithm(data));
    block_on(learn_rust());
}

async fn learn_data_structure_and_algorithm() {
    let data = learn_data_structure().await;
    learn_algorithm(data).await;
}

async fn async_main() {
    let future1 = learn_data_structure();
    let future2 = learn_rust();
    join!(future1, future2);// join!()只能在async函数闭包或者块内使用
}

fn six() {
    block_on(async_main());
}
